#include "DeviceSpikeHelper.h"

#include <QDebug>

#include "ConstData.h"
#include "ConstNames.h"
#include "ModbusManager.h"

// BCD转换函数
static int bcdToInt(quint8 bcd) { return ((bcd >> 4) & 0x0F) * 10 + (bcd & 0x0F); }

static quint8 intToBcd(int value) { return ((value / 10) << 4) | (value % 10); }
#define REG_SYSTEM_STATE 0x03      // 系统状态
#define REG_SYSTEM_ERROR 0x0D      // 系统错误
#define REG_SAMPLING_CONTROL 0x99  // 采样控制寄存器
#define REG_CLEAN_CONTROL 0x9A     // 清洗控制寄存器
#define REG_TIME_YEAR_MONTH 0x6B   // 时钟：年(高8位)+月(低8位)
#define REG_TIME_DAY_HOUR 0x6C     // 时钟：日(高8位)+时(低8位)
#define REG_TIME_MIN_SEC 0x6D      // 时钟：分(高8位)+秒(低8位)

// 控制命令值
#define CONTROL_START 1  // 启动
#define CONTROL_STOP 0   // 停止

// 加标设备状态定义
typedef enum {
    STATE_IDLE = 0,            // 空闲
    STATE_DRAIN_BUFFER_TANK,   // 缓存罐排空
    STATE_CLEAN_BUFFER_SLOT,   // 缓存槽清洗
    STATE_BLOW,                // 鼓吹
    STATE_RINSE_BUFFER_TANK,   // 缓存罐润洗
    STATE_ADD_REAGENT,         // 添加试剂
    STATE_BUFFER_TANK_SAMPLE,  // 缓存罐进样
    STATE_CLEAN_REAGENT_PIPE,  // 试剂管路清洗
    STATE_ANALYZER_ANALYZING,  // 分析仪分析中
} spike_state_t;

typedef enum {
    CMD_SKIPE = 1,           // 启动加标
    CMD_CLEAN = 2,           // 清洗
    CMD_STOP_SKIPE = 3,      // 停止加标
    CMD_STOP_CLEAN = 4,      // 停止清洗
    CMD_SET_TIME = 5,        // 确定校时
    CMD_STOP_ALL = 6,        // 停止所有操作
    CMD_RECOVERY_START = 7,  // 加标回收启动

} spike_cmd_t;

// 操作到寄存器地址的映射
static const QMap<quint16, quint16> SPIKE_CMD_ADDR_MAP = {
    {CMD_SKIPE, REG_SAMPLING_CONTROL},
    {CMD_STOP_SKIPE, REG_SAMPLING_CONTROL},
    {CMD_CLEAN, REG_CLEAN_CONTROL},
    {CMD_STOP_CLEAN, REG_CLEAN_CONTROL},
};

// 操作到控制值的映射
static const QMap<quint16, quint16> SPIKE_CMD_VALUE_MAP = {
    {CMD_SKIPE, CONTROL_START},
    {CMD_STOP_SKIPE, CONTROL_STOP},
    {CMD_CLEAN, CONTROL_START},
    {CMD_STOP_CLEAN, CONTROL_STOP},
};

static const QMap<QString, quint16> SPIKE_OPERATE_MAP = {
    // {OperationNames::SPIKE_INTAKE, CMD_SKIPE},
    // {OperationNames::SPIKE_INTAKE_STOP, CMD_STOP_SKIPE},
    {OperationNames::SPIKE_DRAIN, CMD_CLEAN},
    {OperationNames::SPIKE_DRAIN_STOP, CMD_STOP_CLEAN},
    {OperationNames::COMMON_SET_TIME, CMD_SET_TIME},
    {OperationNames::COMMON_STOP, CMD_STOP_ALL},
    {OperationNames::SPIKE_RECOVERY_START, CMD_RECOVERY_START},

};

static const QMap<quint16, QString> SPIKE_STATE_MAP = {
    {STATE_IDLE, StateNames::SPIKE_STATE_IDLE},
    {STATE_DRAIN_BUFFER_TANK, StateNames::SPIKE_STATE_DRAIN_BUFFER_TANK},
    {STATE_CLEAN_BUFFER_SLOT, StateNames::SPIKE_STATE_CLEAN_BUFFER_SLOT},
    {STATE_BLOW, StateNames::SPIKE_STATE_BLOW},
    {STATE_RINSE_BUFFER_TANK, StateNames::SPIKE_STATE_RINSE_BUFFER_TANK},
    {STATE_ADD_REAGENT, StateNames::SPIKE_STATE_ADD_REAGENT},
    {STATE_BUFFER_TANK_SAMPLE, StateNames::SPIKE_STATE_BUFFER_TANK_SAMPLE},
    {STATE_CLEAN_REAGENT_PIPE, StateNames::SPIKE_STATE_CLEAN_REAGENT_PIPE},
    {STATE_ANALYZER_ANALYZING, StateNames::SPIKE_STATE_ANALYZER_ANALYZING},
};

typedef enum {
    ERROR_NONE = 0,             // 无错误
    ERROR_FRIDGE_TEMP_LOW,      // 冰箱温度过低
    ERROR_FRIDGE_TEMP_HIGH,     // 冰箱温度过高
    ERROR_TEMPERATURE,          // 温度故障
    ERROR_SCREEN_CONNECTION,    // 屏连接失败
    ERROR_SPIKE_REAGENT_LOW,    // 加标标液不足
    ERROR_MEASURE_REAGENT_LOW,  // 测量标液不足
    ERROR_ZERO_LIQUID_LOW,      // 零液不足
    ERROR_SPIKE_TANK_LOW,       // 加标罐低液位故障
    ERROR_SPIKE_TANK_HIGH,      // 加标罐高液位故障
    ERROR_MEASURE_LIQUID,       // 测量液误差过大
    ERROR_ZERO_LIQUID,          // 零液核查误差过大
    ERROR_SPIKE_RECOVERY_RATE,  // 加标回收率误差过大
    ERROR_REAGENT_EXPIRED,      // 试剂过期
} spike_error_type_t;

static const QMap<quint16, QString> SPIKE_ERROR_TYPE_MAP = {
    {ERROR_NONE, ErrorNames::COMMON_ERROR_NONE},
    {ERROR_FRIDGE_TEMP_LOW, ErrorNames::SPIKE_ERROR_FRIDGE_TEMP_LOW},
    {ERROR_FRIDGE_TEMP_HIGH, ErrorNames::SPIKE_ERROR_FRIDGE_TEMP_HIGH},
    {ERROR_TEMPERATURE, ErrorNames::SPIKE_ERROR_TEMPERATURE},
    {ERROR_SCREEN_CONNECTION, ErrorNames::SPIKE_ERROR_SCREEN_CONNECTION},
    {ERROR_SPIKE_REAGENT_LOW, ErrorNames::SPIKE_ERROR_SPIKE_REAGENT_LOW},
    {ERROR_MEASURE_REAGENT_LOW, ErrorNames::SPIKE_ERROR_MEASURE_REAGENT_LOW},
    {ERROR_ZERO_LIQUID_LOW, ErrorNames::SPIKE_ERROR_ZERO_LIQUID_LOW},
    {ERROR_SPIKE_TANK_LOW, ErrorNames::SPIKE_ERROR_SPIKE_TANK_LOW},
    {ERROR_SPIKE_TANK_HIGH, ErrorNames::SPIKE_ERROR_SPIKE_TANK_HIGH},
    {ERROR_MEASURE_LIQUID, ErrorNames::SPIKE_ERROR_MEASURE_LIQUID},
    {ERROR_ZERO_LIQUID, ErrorNames::SPIKE_ERROR_ZERO_LIQUID},
    {ERROR_SPIKE_RECOVERY_RATE, ErrorNames::SPIKE_ERROR_SPIKE_RECOVERY_RATE},
    {ERROR_REAGENT_EXPIRED, ErrorNames::SPIKE_ERROR_REAGENT_EXPIRED},
};

/* 配置项名称映射 */
static const QVariantMap DEVICE_CONFIG_MAP = {
    {ConfigNames::SPIKE_CONFIG_MULTIPLIER, 0.0},     // 加标倍数
    {ConfigNames::SPIKE_CONFIG_CONCENTRATION, 0.0},  // 加标浓度
    {ConfigNames::SPIKE_CONFIG_VOLUME, 0.0},         // 加标体积
};
DeviceSpikeHelper::DeviceSpikeHelper(QString deviceName, QObject* parent)
    : IDevice(deviceName, parent),
      m_modbusManager(ModbusManager::instance()),
      m_stepTimer(new QTimer(this)),
      m_currentSpikeRecoveryStep(SpikeRecoveryStep::IDLE),
      m_concentration1(0.0f),
      m_concentration2(0.0f),
      m_recoveryRate(0.0f),
      m_baselineValue1(0.0f),
      m_baselineValue2(0.0f),
      m_isFirstRead1(true),
      m_isFirstRead2(true),
      m_isSpikeRecoveryMode(false)
{
    m_operateMap = SPIKE_OPERATE_MAP;
    m_statusMap = SPIKE_STATE_MAP;
    m_errorMap = SPIKE_ERROR_TYPE_MAP;
    // m_configMap = DEVICE_CONFIG_MAP;

    // 设置定时器
    m_stepTimer->setSingleShot(true);
    m_stepTimer->setInterval(STEP_TIMEOUT_MS);
    connect(m_stepTimer, &QTimer::timeout, this, &DeviceSpikeHelper::onStepTimeout);

    // 加载加标回收配置
    loadSpikeRecoveryConfig();

    qDebug() << "initialized with device name:" << m_deviceName;
}

DeviceSpikeHelper::~DeviceSpikeHelper()
{
    qDebug() << "destroyed for device name:" << m_deviceName;
}

void DeviceSpikeHelper::control(quint16 optCode)
{
    // 每次操作前清零软件管理的错误码，从干净状态开始
    m_deviceData.faultCode = ERROR_NONE;

    quint16 addr = SPIKE_CMD_ADDR_MAP.value(optCode, 0);
    quint16 data = SPIKE_CMD_VALUE_MAP.value(optCode, 0);
    if (optCode == CMD_RECOVERY_START) {
        // 加标回收启动
        startSpikeRecovery();
        return;
    }
    if (optCode == CMD_STOP_ALL) {
        // 停止所有操作
        stop();
        return;
    }
    IDevice::control(addr, data);
}

void DeviceSpikeHelper::onGetDeviceData()
{
    if (m_busyFlags.dataBusy) {
        return;
    }
    m_busyFlags.dataBusy = true;

    ModbusHelper* modbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    if (!modbus) {
        qDebug() << "Failed to get ModbusHelper for device:" << m_deviceName;
        m_busyFlags.dataBusy = false;
        return;
    }
    modbus->asyncRead(REG_SYSTEM_STATE, 1)
        .then([this, modbus](const QVector<quint16>& result) {
            m_deviceData.status = result[0];
            m_isIdle = m_deviceData.status == STATE_IDLE;
            return modbus->asyncRead(REG_SYSTEM_ERROR, 1);
        })
        .then([this, modbus](const QVector<quint16>& result) {
            quint16 deviceRawFaultCode = result[0];  // 设备原始错误码

            // 检测到新错误时才更新软件管理的错误码
            if (deviceRawFaultCode != m_lastFaultCode && deviceRawFaultCode != ERROR_NONE) {
                m_deviceData.faultCode = deviceRawFaultCode;  // 更新软件错误码
                for (int i = 0; i < 16; ++i) {
                    if (deviceRawFaultCode & (1 << i)) {
                        emit errorOccurred(QString("%1").arg(getErrorName(i + 1)));
                    }
                }
            }
            m_lastFaultCode = deviceRawFaultCode;
            return modbus->asyncRead(REG_TIME_YEAR_MONTH, 3);  // 读取3个时间寄存器
        })
        .then([this](const QVector<quint16>& result) {
            // 解析时间数据
            quint16 yearMonth = result[0];
            quint16 dayHour = result[1];
            quint16 minSec = result[2];

            // BCD码转换
            int year = bcdToInt((yearMonth >> 8) & 0xFF);  // 高8位：年
            int month = bcdToInt(yearMonth & 0xFF);        // 低8位：月
            int day = bcdToInt((dayHour >> 8) & 0xFF);     // 高8位：日
            int hour = bcdToInt(dayHour & 0xFF);           // 低8位：时
            int minute = bcdToInt((minSec >> 8) & 0xFF);   // 高8位：分
            int second = bcdToInt(minSec & 0xFF);          // 低8位：秒

            // 年份可能需要处理（如果是两位数年份，需要转换为四位数）
            if (year < 100) {
                year += 2000;  // 假设是21世纪
            }

            QDateTime datetime(QDate(year, month, day), QTime(hour, minute, second));
            m_deviceData.datetime = datetime;
            emit deviceDataChanged(m_deviceData);
        })
        .finally([this]() { m_busyFlags.dataBusy = false; });
}

void DeviceSpikeHelper::setDeviceTime(const QDateTime& datetime)
{
    if (m_busyFlags.controlBusy) {
        return;
    }
    m_busyFlags.controlBusy = true;

    ModbusHelper* modbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    if (!modbus) {
        qDebug() << "Failed to get ModbusHelper for device:" << m_deviceName;
        m_busyFlags.controlBusy = false;
        return;
    }

    // 准备时间数据
    int year = datetime.date().year();
    int month = datetime.date().month();
    int day = datetime.date().day();
    int hour = datetime.time().hour();
    int minute = datetime.time().minute();
    int second = datetime.time().second();

    // 如果年份是四位数，转换为两位数（取后两位）
    if (year >= 2000) {
        year = year - 2000;
    }

    // 转换为BCD码并组合寄存器数据
    quint16 yearMonth = (intToBcd(year) << 8) | intToBcd(month);  // 年(高8位) + 月(低8位)
    quint16 dayHour = (intToBcd(day) << 8) | intToBcd(hour);      // 日(高8位) + 时(低8位)
    quint16 minSec = (intToBcd(minute) << 8) | intToBcd(second);  // 分(高8位) + 秒(低8位)

    QVector<quint16> data;
    data << yearMonth << dayHour << minSec;

    modbus->asyncWrite(REG_TIME_YEAR_MONTH, data)
        .fail([this](const QString& error) {
            qDebug() << "Failed to write time registers for device:" << m_deviceName
                     << "Error:" << error;
        })
        .finally([this]() { m_busyFlags.controlBusy = false; });
}

void DeviceSpikeHelper::stopSpikeRecovery()
{
    if (m_busyFlags.controlBusy) {
        return;
    }

    // 停止加标回收流程
    if (m_isSpikeRecoveryMode) {
        m_stepTimer->stop();
        m_currentSpikeRecoveryStep = SpikeRecoveryStep::IDLE;
        m_isSpikeRecoveryMode = false;

        // 重置轮询标志
        m_isFirstRead1 = true;
        m_isFirstRead2 = true;
    }

    m_busyFlags.controlBusy = true;

    ModbusHelper* modbus = ModbusManager::instance()->getModbusHelper(m_deviceName);
    if (!modbus) {
        qDebug() << "Failed to get ModbusHelper for device:" << m_deviceName;
        m_busyFlags.controlBusy = false;
        return;
    }

    QVector<quint16> data;
    data << 0 << 0;

    modbus->asyncWrite(REG_SAMPLING_CONTROL, data)
        .fail([this](const QString& error) {
            qDebug() << "Failed to write stop command for device:" << m_deviceName
                     << "Error:" << error;
        })
        .finally([this]() { m_busyFlags.controlBusy = false; });
}